import type Mapless from '..';
import type { IManager, ManagerOptions } from '../index.d';
import EventEmitter from './event';
import type { IdHubType } from './IdHub';
import Listener from './Listener';

export const genPrefixId = (prefix = '') =>
  `${prefix}-${Date.now()}-${Math.floor(Math.random() * 10000)}`;

// 无需super定义为箭头函数或abstract，否则定义为普通成员函数
export abstract class Manager<T extends IdHubType = IdHubType>
  implements IManager
{
  protected map: mapboxgl.Map | null = null;
  protected mapless: Mapless | null = null;

  public gmid: string;
  protected beforeManagers: IManager[] | null = null;
  protected beforeManagersNameList: string[] | null = null;

  public IsVisible = true;

  idHub: T | undefined;

  constructor(mapless: Mapless, options?: ManagerOptions, prefix?: string) {
    this.map = mapless.map;
    this.mapless = mapless;
    const opts = options ? options : {};
    opts.prefix = opts.prefix || prefix;
    this.gmid = this.genId(opts?.prefix || '');
    this.beforeManagers = opts?.beforeManagers || null;
    this.beforeManagersNameList = opts?.beforeManagersNameList || null;
  }

  protected onInitialized() {
    this.createIdHub();
    this.initLayers();
  }

  createIdHub(idHub?: T | undefined) {
    this.idHub = idHub;
    // idHub中包含所有id:layers or sources
    this.idHub?.updateIds((_key, value, _type) => `${value}-${this.gmid}`);
  }

  // TODO addEmptySource是否要延迟执行？
  initLayers() {}

  activeBeforeManager() {
    this.beforeManagers?.forEach((bm) => {
      this.mapless?.moveManagerLayers(this, bm);
    });
    this.beforeManagersNameList?.forEach((bmName) => {
      const bm = this.mapless?.getByName(bmName);
      this.mapless?.moveManagerLayers(this, bm);
    });
  }

  setVisible(visible: boolean) {
    this.IsVisible = visible;
    if (!this.mapless || !this.idHub) return;
    const layers = this.idHub.getAllLayers();
    Object.entries(layers).forEach(([_, layerId]) => {
      // this.mapless?.toggleLayer(layerId, visible);
      if (this.mapless?.getLayer(layerId)) {
        this.mapless.setLayoutProperty(
          layerId,
          'visibility',
          visible ? 'visible' : 'none',
        );
      }
    });
  }

  /**
   * 开关mana中图层监听的事件
   * @param _interaction 开关-on_off
   */
  setInteraction(_interaction: boolean) {}

  mapZoomHandler = () => {};

  onStyleChanged = (_tag: string) => {};

  getDatas(): unknown[] {
    return [];
  }

  /**
   * 获取当前manager管理的所有图层id
   * @description 注意不要返回mapboxgl的默认图层id
   * @description 注意要对应定义时图层顺序
   * @returns string[]
   */
  getLayerIds = () => {
    return this.idHub?.getAllLayersIdList() || [];
  };

  genId = (prefix = 'gm') => genPrefixId(prefix);

  // TODO 根据对应的Feature或GeoJSON统一处理fit区域
  fitBounds = () => {};

  destroy() {
    Object.values(this.idHub?.getAllLayers() || {}).forEach((layerId) => {
      if (this.mapless?.getLayer(layerId)) {
        this.mapless.removeLayer(layerId);
      }
    });
    Object.values(this.idHub?.getAllSources() || {}).forEach((sourceId) => {
      if (this.mapless?.getSource(sourceId)) {
        this.mapless.removeSource(sourceId);
      }
    });
  }
}

export abstract class EmitManager<
  T extends Record<string, unknown[]>,
  P extends IdHubType = IdHubType,
> extends Manager<P> {
  protected emitter = new EventEmitter<T>();
  protected _listener: Listener | undefined;

  constructor(mapless: Mapless, options?: ManagerOptions, prefix?: string) {
    super(mapless, options, prefix);
    this._listener = new Listener(this.mapless?.map);
  }

  // ((keyof T) | string)
  on = <K extends keyof T>(event: K, handler: (...payload: T[K]) => void) => {
    this.emitter.on(event, handler);
    return this;
  };

  off = <K extends keyof T>(event: K, handler: (...payload: T[K]) => void) => {
    this.emitter.off(event, handler);
    return this;
  };

  emit = <K extends keyof T>(event: K, ...payload: T[K]) => {
    this.emitter.emit(event, ...payload);
    return this;
  };

  override setInteraction(interaction: boolean) {
    if (interaction) {
      this._listener?.reconnect2Map();
    } else {
      this._listener?.disconnect4Map();
    }
  }

  override destroy(): void {
    super.destroy();
    this._listener?.removeAll();
    this._listener = undefined;
  }
}
